using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using System;
using System.Numerics;

namespace IQIGame.Onigao.Logic
{
    /// <summary>
    /// 逻辑层方便几何运算的OBB矩形，顶点顺序为左下角开始，顺时针旋转
    /// 注意该矩形内的计算并非都是定点数计算（因为会使用到Matrix3x2），后续可能会根据需求调整为全浮点数或全定点数
    /// 
    /// 该类的特点是存储了4个顶点，通过4个顶点，可以进行带旋转的矩形几何运算，不同于FixedOBBRect，FixedOBBRect是专门用于碰撞的，优化了性能，但无法直接获取顶点
    /// 该类支持传入任意矢量和方向矢量来进行坐标系变换，且可以直接还原到原来的坐标系
    /// 
    /// 可以和GeometryUtil配合使用
    /// </summary>
    public class TransableVertexOBBRect : IReusableClass
    {
        public uint MaxStore => 20;
        //变换坐标系时使用的矩阵的逆矩阵
        private Matrix3x2 inverseMatrix = Matrix3x2.Identity;
        //变换坐标系时使用的新原点
        private Vector2Logic newOrigin = Vector2Logic.zero;
        public float width { get; private set; }
        public float height { get; private set; }

        #region 原始值（变换前的）
        public Vector2Logic originalCenter { get; private set; }
        public Vector2Logic[] originalVertices { get; } = new Vector2Logic[4];
        #endregion

        #region 当前值（可能是变换后的）
        private Vector2Logic axisY;
        public Vector2Logic center { get; private set; }
        public Vector2Logic[] vertices { get; } = new Vector2Logic[4];
        public float minX { get; private set; } = float.MaxValue;
        public float maxX { get; private set; } = float.MinValue;
        public float minY { get; private set; } = float.MaxValue;
        public float maxY { get; private set; } = float.MinValue;
        #endregion

        public void Init(Vector2Logic center, float width, float height, float rotation)
        {
            this.width = width;
            this.height = height;
            originalCenter = center;
            this.center = center;
            float halfW = width / 2;
            float halfH = height / 2;
            originalVertices[0] = new Vector2Logic(center.x - halfW, center.y - halfH);
            originalVertices[1] = new Vector2Logic(center.x + halfW, center.y - halfH);
            originalVertices[2] = new Vector2Logic(center.x + halfW, center.y + halfH);
            originalVertices[3] = new Vector2Logic(center.x - halfW, center.y + halfH);
            if (rotation == 0) //不带旋转
            {
                axisY = new Vector2Logic(0, 1);
            }
            else //带旋转
            {
                float rotationRad = rotation * MathLogic.Deg2Rad;
                Vector2Logic axisX = new Vector2Logic((float)Math.Cos(rotationRad), -(float)Math.Sin(rotationRad));
                axisY = new Vector2Logic(-axisX.y, axisX.x);
                for (int i = 0; i < originalVertices.Length; i++)
                {
                    // 将坐标移动到原点
                    Vector2Logic point = originalVertices[i] - originalCenter;
                    // 将坐标转换到新的坐标系
                    Vector2Logic rotatedPoint = new Vector2Logic(Vector2Logic.Dot(point, axisX), Vector2Logic.Dot(point, axisY));
                    // 移动回原来的位置
                    originalVertices[i] = rotatedPoint + originalCenter;
                }
            }
            for (int i = 0; i < originalVertices.Length; i++)
            {
                Vector2Logic v = originalVertices[i];
                vertices[i] = v;
                minX = Math.Min(minX, v.x);
                maxX = Math.Max(maxX, v.x);
                minY = Math.Min(minY, v.y);
                maxY = Math.Max(maxY, v.y);
            }
        }

        /// <summary>
        /// 根据新的原点和Y轴，变换顶点坐标
        /// </summary>
        /// <param name="newOrigin">新的原点</param>
        /// <param name="newAxisY">新的y轴方向</param>
        public void TransformByNewAxis(Vector2Logic newOrigin, Vector2Logic newAxisY)
        {
            this.newOrigin = newOrigin;
            if (this.axisY == newAxisY)
            {
                for (int i = 0; i < originalVertices.Length; i++)
                {
                    vertices[i] = originalVertices[i] - newOrigin;
                }
                center = originalCenter - newOrigin;
            }
            else
            {
                this.axisY = newAxisY;
                Vector2Logic axisX = new Vector2Logic(newAxisY.y, -newAxisY.x);
                Matrix3x2 transform = new Matrix3x2((float)axisX.x, -(float)axisX.y, -(float)newAxisY.x, (float)newAxisY.y, 0, 0);
                //逆矩阵（变换矩阵是正交矩阵，没有调用Invert）
                inverseMatrix = new Matrix3x2((float)axisX.x, -(float)newAxisY.x, -(float)axisX.y, (float)newAxisY.y, 0, 0);
                for (int i = 0; i < originalVertices.Length; i++)
                {
                    //先把顶点按照newOrigin转换到本地坐标系，再进行变换
                    Vector2Logic v = Transform(originalVertices[i] - newOrigin, transform);
                    vertices[i] = v;
                }
                center = Transform(originalCenter - newOrigin, transform);
            }
            minX = float.MaxValue;
            maxX = float.MinValue;
            minY = float.MaxValue;
            maxY = float.MinValue;
            for (int i = 0; i < vertices.Length; i++)
            {
                Vector2Logic v = vertices[i];
                minX = Math.Min(minX, v.x);
                maxX = Math.Max(maxX, v.x);
                minY = Math.Min(minY, v.y);
                maxY = Math.Max(maxY, v.y);
            }
        }

        /// <summary>
        /// 矩阵变换（非定点数计算）
        /// </summary>
        /// <param name="position"></param>
        /// <param name="matrix"></param>
        /// <returns></returns>
        private static Vector2Logic Transform(Vector2Logic position, Matrix3x2 matrix)
        {
            return new Vector2Logic(position.x * matrix.M11 + position.y * matrix.M21 + matrix.M31, position.x * matrix.M12 + position.y * matrix.M22 + matrix.M32);
        }

        /// <summary>
        /// 将任意矢量按照当前矩形坐标变换的逆运算还原到原始坐标系
        /// </summary>
        /// <param name="v1"></param>
        /// <returns></returns>
        public Vector2Logic RevertVectorToOrigin(Vector2Logic v1)
        {
            return Transform(v1, inverseMatrix) + newOrigin;
        }

        public void OnReset()
        {
            minX = float.MaxValue;
            maxX = float.MinValue;
            minY = float.MaxValue;
            maxY = float.MinValue;
            width = 0;
            height = 0;
            axisY = default;
            originalCenter = default;
            center = default;
            for (int i = 0; i < originalVertices.Length; i++)
            {
                originalVertices[i] = default;
                vertices[i] = default;
            }
        }
    }
}
